òɾۿûѧϰʹá
ԭַhttps://www.joinquant.com/post/15002

ԭһ˵ʽ鵽ԭĺ߽ۡ


ԭĲԴ£

'''
˼·
ѡɣָѡ
ʱRSRSʱ
ֲ֣пźʱ10ֻƱʱֿղ

'''
# 뺯
import statsmodels.api as sm
from pandas.stats.api import ols

# ʼ趨׼ȵ
def initialize(context):
    # ̬Ȩģʽ(ʵ۸)
    set_option('use_real_price', True)
    # ˵orderϵAPIıerror͵log
    # log.set_level('order', 'error')
    set_parameter(context)
    ### Ʊ趨 ###
    # ƱÿʽʱǣʱӶ֮ʱӶ֮ǧ֮һӡ˰, ÿʽӶͿ5Ǯ
    set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
    
    ## кreference_securityΪʱĲοģıֻ֣˴'000300.XSHG''510300.XSHG'һģ
      # ǰ
    run_daily(before_market_open, time='before_open', reference_security='000300.XSHG') 
      # ʱ
    run_daily(market_open, time='open', reference_security='000300.XSHG')
      # ̺
    #run_daily(after_market_close, time='after_close', reference_security='000300.XSHG')
    
'''
==============================ò================================
'''
def set_parameter(context):
    # RSRSָN, Mֵ
    #ͳ
    g.N = 18
    #ͳ
    g.M = 1100
    #״ж
    g.init = True
    #ֲֹƱ
    g.stock_num = 10
    #ղο׼
    g.security = '000300.XSHG'
    # 趨л׼
    set_benchmark(g.security)
    #¼
    g.days = 0
    #set_benchmark(g.stock)
    # ֵ
    g.buy = 0.7
    g.sell = -0.7
    #ڼ¼عbetaֵб
    g.ans = []
    #ڼ㱻ϵȨıֵ
    g.ans_rightdev= []
    
    # 200515ز⿪ʼڵRSRSбָ
    prices = get_price(g.security, '2005-01-05', context.previous_date, '1d', ['high', 'low'])
    highs = prices.high
    lows = prices.low
    g.ans = []
    for i in range(len(highs))[g.N:]:
        data_high = highs.iloc[i-g.N+1:i+1]
        data_low = lows.iloc[i-g.N+1:i+1]
        X = sm.add_constant(data_low)
        model = sm.OLS(data_high,X)
        results = model.fit()
        g.ans.append(results.params[1])
        #r2
        g.ans_rightdev.append(results.rsquared)
    
## ǰк     
def before_market_open(context):
    # ʱ
    #log.info('ʱ(before_market_open)'+str(context.current_dt.time()))
    g.days += 1
    # ΢ŷϢģ⽻ף΢Ч
    send_message('е%s~'%g.days)

## ʱк
def market_open(context):
    security = g.security
    # ڵRSRSбֵ
    beta=0
    r2=0
    if g.init:
        g.init = False
    else:
        #RSRSбָ궨
        prices = attribute_history(security, g.N, '1d', ['high', 'low'])
        highs = prices.high
        lows = prices.low
        X = sm.add_constant(lows)
        model = sm.OLS(highs, X)
        beta = model.fit().params[1]
        g.ans.append(beta)
        #r2
        r2=model.fit().rsquared
        g.ans_rightdev.append(r2)
    
    # ׼RSRSָ
    # ֵ    
    section = g.ans[-g.M:]
    # ֵ
    mu = np.mean(section)
    # ׼RSRSָ
    sigma = np.std(section)
    zscore = (section[-1]-mu)/sigma  
    #ƫRSRS׼
    zscore_rightdev= zscore*beta*r2
    
    # һʱRSRSбʴֵ, ȫ
    if zscore_rightdev > g.buy:
        # ¼
        log.info("гںΧ")
        #н
        trade_func(context)
    # һʱRSRSбСֵ, ղ
    elif (zscore_rightdev < g.sell) and (len(context.portfolio.positions.keys()) > 0):
        # ¼
        log.info("гչ󣬱ֿղ״̬")
        # йƱ,ʹֻƱճΪ0
        for s in context.portfolio.positions.keys():
            order_target(s, 0)
            
#ѡ    
def trade_func(context):
    #ȡƱ
    df = get_fundamentals(query(valuation.code,valuation.pb_ratio,indicator.roe))
    #pb,roe0ɸѡ
    df = df[(df['roe']>0) & (df['pb_ratio']>0)].sort('pb_ratio')
    #ԹƱΪindex
    df.index = df['code'].values
    #ȡroe
    df['1/roe'] = 1/df['roe']
    #ȡۺϵ÷
    df['point'] = df[['pb_ratio','1/roe']].rank().T.apply(f_sum)
    #÷ֽȡָĹƱ
    df = df.sort('point')[:g.stock_num]
    pool = df.index
    log.info('ܹѡ%sֻƱ'%len(pool))
    #õÿֻƱӦ÷ʽ
    cash = context.portfolio.total_value/len(pool)
    #ȡѾֲб
    hold_stock = context.portfolio.positions.keys() 
    #ڳֲеĹƱ
    for s in hold_stock:
        if s not in pool:
            order_target(s,0)
    #Ʊ
    for s in pool:
        order_target_value(s,cash)
#ֹ
def f_sum(x):
    return sum(x)
        
## ̺к  
def after_market_close(context):
    #õгɽ¼
    trades = get_trades()
    for _trade in trades.values():
        log.info('ɽ¼'+str(_trade))
    #ӡ˻ʲ
    log.info('˻ʲ%s'%round(context.portfolio.total_value,2))
    #log.info('##############################################################')
